/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Basketball;

import VISIE.Main;
import VISIE.characters.BasketballAgent;
import VISIE.characters.BasketballCharacter;
import VISIE.mathfunctions.Conversions;
import VISIE.models.AnimatedModel;
import com.jme3.math.Vector3f;
import VISIE.characters.Character;
import VISIE.models.BasketballPlayerModel;
import VISIE.scenemanager.SceneCharacterManager;
import com.jme3.animation.LoopMode;
import com.jme3.math.Ray;

/**
 *
 * @author DiveshLala
 */
public class AgentBodyOperations {
    
    BasketballAgent parentCharacter;
    AnimatedModel agentModel;
    float headRotationAngle;
    float torsoRotationAngle;
//    private float maxSpeed;
//    private float turningSpeed;
    private float rangeOfVision;
//    private float headMaxTurningAngle;
     private float headTurnSpeed = 0.25f; //degrees per frame
    private float torsoTurnSpeed = 0.25f; //degrees per frame
    private float walkSpeed = 3;
    private float runSpeed = 4;
    private float shuffleSpeed = 2;
    private float dribbleSpeed = 2.5f;
            
    private int turnCode = 0;

   // private float mutualGazeAngle;
    
    public AgentBodyOperations(BasketballAgent ba, AnimatedModel m){
        
        parentCharacter = ba;
        agentModel = m;
        headRotationAngle = 0;
        torsoRotationAngle = 0;
    }
    
    public void turnHeadToTarget(Vector3f target){
        float targetAngle = Conversions.originToTargetAngle(parentCharacter.getPosition(), target);
        if(Math.abs(targetAngle - headRotationAngle) > 5){
            float f = Conversions.calculateSpinDirection(targetAngle, headRotationAngle);
            headRotationAngle = Conversions.adjustAngleTo360(headRotationAngle + (headTurnSpeed * -f * (Main.getFrameRate() * 200)));
            this.setFacingDirection(torsoRotationAngle, headRotationAngle);
        }
    }
    
    public void setHeadAngle(Vector3f vec){
        headRotationAngle = Conversions.originToTargetAngle(parentCharacter.getPosition(), vec);
    }
    
    public void turnTorsoToTarget(Vector3f target){
        float targetAngle = Conversions.originToTargetAngle(parentCharacter.getPosition(), target);
            if(Math.abs(targetAngle - torsoRotationAngle) > 5){
                float f = Conversions.calculateSpinDirection(targetAngle, torsoRotationAngle);
                torsoRotationAngle = Conversions.adjustAngleTo360(torsoRotationAngle + (torsoTurnSpeed * -f * (Main.getFrameRate() * 200)));
                this.setFacingDirection(torsoRotationAngle, headRotationAngle);
                
                if(f < 0){
                    turnCode = 1;
                }
                else{
                    turnCode = 2;
                }    
            }
            else{
                turnCode = 0;
            }
    }
    
    public void setFacingDirection(float torsoRotation, float headRotation){ 
        headRotationAngle = headRotation;
        torsoRotationAngle = torsoRotation;
        agentModel.turnBody(headRotationAngle - torsoRotationAngle, torsoRotationAngle);
    }
    
    public void turnBodyToTarget(Vector3f target){
        this.turnHeadToTarget(target);
        this.turnTorsoToTarget(target);
    }
    
    public boolean isReadyForPass(Character c){
        return (Math.abs(torsoRotationAngle - Conversions.originToTargetAngle(parentCharacter.getPosition(), c.getPosition())) < 5);
    }
        
    public float getFacingDirection(){
        return torsoRotationAngle;
    }
    
    public float getHeadRotationAngle(){
        return headRotationAngle;
    }
    
    public void moveTowardsTarget(Vector3f target){ //agent has not yet reached target
        
        Vector3f realTarget = target; 
        
        if(parentCharacter.perception.isCollisionPredicted(target)){
            realTarget = parentCharacter.perception.avoidCollision(target);
        }
        
        //agent is looking straight at target
        if(parentCharacter.perception.isLookingAtTarget(realTarget)){
            this.turnBodyToTarget(realTarget);
            Vector3f dir = Conversions.degreesToNormalizedCoordinates(Conversions.originToTargetAngle(parentCharacter.getPosition(), realTarget)); 
            if(realTarget.setY(0).distance(parentCharacter.getPosition().setY(0)) < 5){
                parentCharacter.setSpeed(walkSpeed);
                parentCharacter.move(dir, parentCharacter.getSpeed());
            }
            else{
                parentCharacter.setSpeed(runSpeed);
                parentCharacter.agentRun(dir, parentCharacter.getSpeed());
            }
            this.doMovingAnimations();
        }
        //agent is in vicinity of target
       //only use stepping in game situation for defense
        else if(GameManager.getGameState() == 0 && 
                !(SceneCharacterManager.getCharacterInPossession() == null) &&
                parentCharacter.get2DPosition().distance(target.setY(0)) < 5){
            if(parentCharacter.planner.defense.getMarkCharacter() != null){
                this.turnBodyToTarget(parentCharacter.planner.defense.getMarkCharacter().getPosition());
            } 
           parentCharacter.setSpeed(shuffleSpeed);
            Vector3f dir = Conversions.degreesToNormalizedCoordinates(Conversions.originToTargetAngle(parentCharacter.getPosition(), realTarget)); 
            parentCharacter.move(dir, parentCharacter.getSpeed());
            this.doSteppingAnimations();
        }
        //agent is not facing target and is far away from it
        //or not in game state
        else{
            parentCharacter.setSpeed(0);  
            this.turnBodyToTarget(realTarget);
            if(this.getFacingToTargetAngle() > 40){
             //   this.doTurningAnimation();
            }
        }
    }
    
    public void doTurningAnimation(){
            
        if(turnCode == 1){
            parentCharacter.playAnimation(2, "stepLeft", runSpeed/2, LoopMode.Loop);
        }
        else if(turnCode == 2){
            parentCharacter.playAnimation(2, "stepRight", runSpeed/2, LoopMode.Loop);
        }
        else{
            parentCharacter.playAnimation(2, "standingPose", runSpeed/2, LoopMode.Loop);
        
        }
    }
    
    
    public void doDribbling(){
        parentCharacter.getModel().doDribbling(dribbleSpeed/10);
    }
    
    public void doMovingAnimations(){
                    
//        System.out.println(parentCharacter.getSpeed() + " " + runSpeed);
        
        
        if(parentCharacter.getSpeed() > 0){ 
           if(parentCharacter.getSpeed() == runSpeed){
                parentCharacter.playAnimation(1, "run", runSpeed/2, LoopMode.Loop);
                parentCharacter.playAnimation(2, "run", runSpeed/2, LoopMode.Loop);
           }
           else{
                parentCharacter.playAnimation(1, "walk", walkSpeed/2, LoopMode.Loop);
                parentCharacter.playAnimation(2, "walk", walkSpeed/2, LoopMode.Loop);  
           }
        }
        else{
        
        }
    }
    
    public void doDribblingAnimations(){
                        
        if(parentCharacter.getSpeed() > 0){
           parentCharacter.playAnimation(2, "walk", dribbleSpeed/2, LoopMode.Loop);
        }
    }
    
    public void doSteppingAnimations(){
        
        float fd = parentCharacter.getFacingDirection();
        float targetAngle = Conversions.originToTargetAngle(parentCharacter.getPosition(), parentCharacter.planner.getTargetPosition());
        
        if(Conversions.minDistanceBetweenAngles(fd, targetAngle) > 120){
            parentCharacter.playAnimation(2, "stepBack", shuffleSpeed/2, LoopMode.Loop);
        }
        
        else{
            if(Conversions.calculateSpinDirection(fd, targetAngle) > 0){
                parentCharacter.playAnimation(2, "stepLeft", shuffleSpeed/2, LoopMode.Loop);
            }
            else{
                parentCharacter.playAnimation(2, "stepRight", shuffleSpeed/2, LoopMode.Loop);
            }
        }
    }
    
    public void dribbleTowardsTarget(Vector3f target){
        
        Vector3f realTarget = target; 

        if(parentCharacter.perception.isCollisionPredicted(target)){
            realTarget = parentCharacter.perception.avoidCollision(target);
        }
        
        if(parentCharacter.perception.isLookingAtTarget(realTarget)){
            this.turnBodyToTarget(realTarget);
            Vector3f dir = Conversions.degreesToNormalizedCoordinates(Conversions.originToTargetAngle(parentCharacter.getPosition(), realTarget)); 
            parentCharacter.setSpeed(dribbleSpeed);
            parentCharacter.move(dir, parentCharacter.getSpeed());
        }
        else if(parentCharacter.get2DPosition().distance(target.setY(0)) < 5){
            parentCharacter.setSpeed(shuffleSpeed);
            Vector3f dir = Conversions.degreesToNormalizedCoordinates(Conversions.originToTargetAngle(parentCharacter.getPosition(), realTarget)); 
            parentCharacter.move(dir, parentCharacter.getSpeed());
        }
        else{
            this.turnBodyToTarget(realTarget);
            parentCharacter.setSpeed(0);
        }
        
        this.doDribblingAnimations();
    }
    
    public void doBlocking(){
        
        BasketballCharacter possessor = SceneCharacterManager.getCharacterInPossession();
        BasketballCharacter markCharacter = (BasketballCharacter)parentCharacter.planner.defense.getMarkCharacter();
        
        if(markCharacter != null){
              this.turnBodyToTarget(parentCharacter.planner.defense.getMarkCharacter().getPosition());
              
              if(markCharacter.equals(possessor)){          
                    parentCharacter.getModel().doBlocking(0.25f);
              }
              else{
                  parentCharacter.playAnimation(1, "standingPose", 1, LoopMode.Loop);
              }
        }
        
    }
    
    public float getFacingToTargetAngle(){
        
        float fd = parentCharacter.getFacingDirection();
        float targetAngle = Conversions.originToTargetAngle(parentCharacter.getPosition(), parentCharacter.planner.getTargetPosition()); 
        return Conversions.minDistanceBetweenAngles(fd, targetAngle) * Conversions.calculateSpinDirection(fd, targetAngle);
        
    }
    
    public void blockingTransition(){
        
        BasketballPlayerModel bm = parentCharacter.getModel();
        
        if(bm.getCurrentAnimation(1).equals("blockLoop")){
           if(bm.hasAnimationFinished(1)){
               parentCharacter.playAnimation(1, "postBlock", 0.25f, LoopMode.DontLoop);
           }
           else{
               bm.setAnimationSpeed(1, 2);
           }
        }
        else if(bm.getCurrentAnimation(1).equals("postBlock")){
           if(bm.hasAnimationFinished(1)){
               parentCharacter.playAnimation(1, "standingPose", 1, LoopMode.DontLoop);
           }            
        }
        else{
            parentCharacter.playAnimation(1, "standingPose", 1, LoopMode.DontLoop);
        }     
    }
    
}
